# encoding: utf-8
#! /usr/bin/env python
'''
Created on 2018年8月14日
description:系统信息收集
@author: zhujianhua
'''
import requests
import time
import json
import sys
import os
import paramiko

sys.path.append('./../helper')
import InfoMonConstants
from LoggerHelper import LoggerHelper


class LinuxsystemInfo:
    def __init__(self, host='127.0.0.1', user='', passwd=''):
        self.host = host
        self.user = user
        self.password = passwd 
        self.uploadData = []  # 收集数据列表
        self.ts = int(time.time()) # 时间戳
        self.logger = LoggerHelper("LinuxsystemInfo")
        self.logger.info('collecting infomation from ' + self.host)

    def run(self):
        if self.host != '127.0.0.1':
            try:
                self.ssh = paramiko.SSHClient()
                self.ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
                self.ssh.connect(self.host,22,self.user,self.password)
            except Exception as e:
                self.logger.error('failed to connect to ' + self.host)
                self.logger.error(str(e))
                return
            else:
                self.collect()
                self.ssh.close()
        else:
            self.collect()
        self.send()

    # 数据收集
    def collect(self):
        try:
            self.getUptime()
            self.getCpus()
            self.getVmstat()
            self.getProcessNum()
            self.getForksNum()
            self.getSwap()
            self.getCpuInfo()
            self.getMemory()
            self.getInodeNum()
            self.getDisk()
            self.getDiskInfo()
            self.getTCPInfo()
            self.getNetworkInfo()
            # self.logger.info(self.uploadData)
        except Exception as e:
            self.logger.error(str(e))
        finally:
            pass

    # 发送数据到transfer
    def send(self):
        if 0 != len(self.uploadData):
            self.logger.info("sending data to " +InfoMonConstants.FALCON_CLINENT)
            try:
                r = requests.post(InfoMonConstants.FALCON_CLINENT, data=json.dumps(self.uploadData))
                self.logger.info(r.text)
            except requests.exceptions.ConnectionError:
                self.logger.error('failed to connect to ' + InfoMonConstants.FALCON_CLINENT)
                self.logger.error('transfer data failed')

    # 执行Linux系统命令，并返回屏幕输出
    def executeCMD(self, cmd):
        if self.host == '127.0.0.1':
            outPut = os.popen(cmd)
            return outPut.read()
        stdin, stdout, stderr = self.ssh.exec_command(cmd)
        return stdout.read()

    def getUptime(self):
        ret = self.executeCMD("uptime")
        retArray = ret.split()
        if retArray[3] == "days":
            uptime = int(retArray[4].split(":")[0])+24*int(retArray[2])
        else:
            arr=retArray[2].split(":")
            if len(arr)==1:
                uptime = format(float(arr[0])/float(60), '.2f')
            else:
                uptime = int(arr[0])
        userNum = retArray[len(retArray)-7]
        shortLA = retArray[len(retArray)-3].rstrip(",")
        mediumLA = retArray[len(retArray)-2].rstrip(",")  # 除去最后的","
        longLA = retArray[len(retArray)-1].rstrip(",")
        self.uploadData.append({  # 主机已运行时间 单位：小时
            "endpoint": InfoMonConstants.ENDPOINT,
            "metric": "system_uptime",
            "timestamp": self.ts,
            "step": 60,
            "value": uptime,
            "counterType": "GAUGE",
            "tags": '',
        })
        self.uploadData.append({  # 用户连接数，是总连接数而不是用户数
            "endpoint": InfoMonConstants.ENDPOINT,
            "metric": "system_user",
            "timestamp": self.ts,
            "step": 60,
            "value": userNum,
            "counterType": "GAUGE",
            "tags": "",
        })
        self.uploadData.append({  # 系统平均负载，统计最近5分钟的系统平均负载
            "endpoint": InfoMonConstants.ENDPOINT,
            "metric": "system_short_load_average",
            "timestamp": self.ts,
            "step": 60,
            "value": shortLA,
            "counterType": "GAUGE",
            "tags": "",
        })
        self.uploadData.append({  # 系统平均负载，统计最近10分钟的系统平均负载
            "endpoint": InfoMonConstants.ENDPOINT,
            "metric": "system_medium_load_average",
            "timestamp": self.ts,
            "step": 60,
            "value": mediumLA,
            "counterType": "GAUGE",
            "tags": "",
        })
        self.uploadData.append({  # 系统平均负载，统计最近15分钟的系统平均负载
            "endpoint": InfoMonConstants.ENDPOINT,
            "metric": "system_long_load_average",
            "timestamp": self.ts,
            "step": 60,
            "value": longLA,
            "counterType": "GAUGE",
            "tags": "",
        })

    def getCpus(self):
        ret = self.executeCMD("cat /proc/cpuinfo| grep \"processor\"| wc -l")
        self.uploadData.append({
            "endpoint": InfoMonConstants.ENDPOINT,
            "metric": "system_CPUs",
            "timestamp": self.ts,
            "step": 60,
            "value": ret.rstrip("\n"),
            "counterType": "GAUGE",
            "tags": "",
        })

    # vmstat命令的监控项
    def getVmstat(self):
        ret = self.executeCMD("vmstat")
        ret = ret.split("\n")[2]
        retArray = ret.split()
        self.uploadData.append({
            "endpoint": InfoMonConstants.ENDPOINT,
            "metric": "system_processes_running",
            "timestamp": self.ts,
            "step": 60,
            "value": retArray[0],
            "counterType": "GAUGE",
            "tags": "",
        })
        self.uploadData.append({
            "endpoint": InfoMonConstants.ENDPOINT,
            "metric": "system_processes_blocked",
            "timestamp": self.ts,
            "step": 60,
            "value": retArray[1],
            "counterType": "GAUGE",
            "tags": "",
        })
        self.uploadData.append({
            "endpoint": InfoMonConstants.ENDPOINT,
            "metric": "system_swap_in",
            "timestamp": self.ts,
            "step": 60,
            "value": retArray[6],
            "counterType": "GAUGE",
            "tags": "",
        })
        self.uploadData.append({
            "endpoint": InfoMonConstants.ENDPOINT,
            "metric": "system_swap_out",
            "timestamp": self.ts,
            "step": 60,
            "value": retArray[7],
            "counterType": "GAUGE",
            "tags": "",
        })
        self.uploadData.append({
            "endpoint": InfoMonConstants.ENDPOINT,
            "metric": "system_context_switches",
            "timestamp": self.ts,
            "step": 60,
            "value": retArray[11],
            "counterType": "GAUGE",
            "tags": "",
        })

    # 统计程数状态
    def getProcessNum(self):
        ret = self.executeCMD("ps -A -o stat|grep -e '^[Zz]'|wc -l")
        self.uploadData.append({
            "endpoint": InfoMonConstants.ENDPOINT,
            "metric": "system_processes_zombies",
            "timestamp": self.ts,
            "step": 60,
            "value": ret.rstrip("\n"),
            "counterType": "GAUGE",
            "tags": "",
        })
        ret = self.executeCMD("ps -A -o stat|grep -e '^[Ss]'|wc -l")
        self.uploadData.append({
            "endpoint": InfoMonConstants.ENDPOINT,
            "metric": "system_processes_sleeping",
            "timestamp": self.ts,
            "step": 60,
            "value": ret.rstrip("\n"),
            "counterType": "GAUGE",
            "tags": "",
        })
        ret = self.executeCMD("ps -A -o stat|grep -e '^[Tt]'|wc -l")
        self.uploadData.append({
            "endpoint": InfoMonConstants.ENDPOINT,
            "metric": "system_processes_stop",
            "timestamp": self.ts,
            "step": 60,
            "value": ret.rstrip("\n"),
            "counterType": "GAUGE",
            "tags": "",
        })

    # 获取forks的数量
    def getForksNum(self):
        ret = self.executeCMD("vmstat -f")
        retArr = ret.split()
        self.uploadData.append({
            "endpoint": InfoMonConstants.ENDPOINT,
            "metric": "system_forks_num",
            "timestamp": self.ts,
            "step": 60,
            "value": retArr[0],
            "counterType": "GAUGE",
            "tags": "",
        })

    # 获取swap使用率
    def getSwap(self):
        ret = self.executeCMD("cat /proc/swaps")
        ret = ret.split("\n")[1]
        retArr = ret.split()
        total = int(retArr[2].rstrip("\n"))
        used = int(retArr[3].rstrip("\n"))
        self.uploadData.append({
            "endpoint": InfoMonConstants.ENDPOINT,
            "metric": "system_swap_usage",
            "timestamp": self.ts,
            "step": 60,
            "value": format(float(used)*100/float(total), '.2f'),
            "counterType": "GAUGE",
            "tags": "%",
        })
        self.uploadData.append({
            "endpoint": InfoMonConstants.ENDPOINT,
            "metric": "system_swap_total",
            "timestamp": self.ts,
            "step": 60,
            "value": total,
            "counterType": "GAUGE",
            "tags": "",
        })
        self.uploadData.append({
            "endpoint": InfoMonConstants.ENDPOINT,
            "metric": "system_swap_used",
            "timestamp": self.ts,
            "step": 60,
            "value": used,
            "counterType": "GAUGE",
            "tags": "",
        })
        self.uploadData.append({
            "endpoint": InfoMonConstants.ENDPOINT,
            "metric": "system_swap_free",
            "timestamp": self.ts,
            "step": 60,
            "value": total-used,
            "counterType": "GAUGE",
            "tags": "",
        })

    # 获取CPU使用信息
    def getCpuInfo(self):
        ret = self.executeCMD("vmstat")
        ret = ret.split("\n")[2]
        retArray = ret.split()
        self.uploadData.append({
            "endpoint": InfoMonConstants.ENDPOINT,
            "metric": "system_cpu_system_usage",
            "timestamp": self.ts,
            "step": 60,
            "value": retArray[-4],
            "counterType": "GAUGE",
            "tags": "%",
        })
        self.uploadData.append({
            "endpoint": InfoMonConstants.ENDPOINT,
            "metric": "system_cpu_user_usage",
            "timestamp": self.ts,
            "step": 60,
            "value": retArray[-5],
            "counterType": "GAUGE",
            "tags": "%",
        })
        self.uploadData.append({
            "endpoint": InfoMonConstants.ENDPOINT,
            "metric": "system_cpu_total_usage",
            "timestamp": self.ts,
            "step": 60,
            "value": 100-int(retArray[-3]),
            "counterType": "GAUGE",
            "tags": "%",
        })
        self.uploadData.append({
            "endpoint": InfoMonConstants.ENDPOINT,
            "metric": "system_cpu_iowait_usage",
            "timestamp": self.ts,
            "step": 60,
            "value": retArray[-2],
            "counterType": "GAUGE",
            "tags": "",
        })

    # 获取memory使用率
    def getMemory(self):
        ret = self.executeCMD("free | grep Mem")
        retArr=ret.split()

        self.uploadData.append({
            "endpoint": InfoMonConstants.ENDPOINT,
            "metric": "system_memory_total_usage",
            "timestamp": self.ts,
            "step": 60,
            "value": format(float(retArr[2])*100/float(retArr[1]), '.2f'),
            "counterType": "GAUGE",
            "tags": "%",
        })
        self.uploadData.append({
            "endpoint": InfoMonConstants.ENDPOINT,
            "metric": "system_memory_total",
            "timestamp": self.ts,
            "step": 60,
            "value": retArr[1],
            "counterType": "GAUGE",
            "tags": "",
        })
        self.uploadData.append({
            "endpoint": InfoMonConstants.ENDPOINT,
            "metric": "system_memory_used",
            "timestamp": self.ts,
            "step": 60,
            "value": retArr[2],
            "counterType": "GAUGE",
            "tags": "",
        })
        self.uploadData.append({
            "endpoint": InfoMonConstants.ENDPOINT,
            "metric": "system_memory_free",
            "timestamp": self.ts,
            "step": 60,
            "value": retArr[3],
            "counterType": "GAUGE",
            "tags": "",
        })
        self.uploadData.append({
            "endpoint": InfoMonConstants.ENDPOINT,
            "metric": "system_memory_buffers",
            "timestamp": self.ts,
            "step": 60,
            "value": retArr[5],
            "counterType": "GAUGE",
            "tags": "",
        })

    # 获取根目录下的inode数量
    def getInodeNum(self):
        ret = self.executeCMD("df -ih")
        retArr = ret.split("\n")[1].split()
        if len(retArr)==1:
            retArr = ret.split("\n")[2].split()
            usedInode=retArr[1]
            freeInode=retArr[2]
        else:
            usedInode=retArr[2]
            freeInode=retArr[3]

        self.uploadData.append({
            "endpoint": InfoMonConstants.ENDPOINT,
            "metric": "system_used_inode",
            "timestamp": self.ts,
            "step": 60,
            "value": usedInode,
            "counterType": "GAUGE",
            "tags": "",
        })
        self.uploadData.append({
            "endpoint": InfoMonConstants.ENDPOINT,
            "metric": "system_free_inode",
            "timestamp": self.ts,
            "step": 60,
            "value": freeInode,
            "counterType": "GAUGE",
            "tags": "",
        })


    # 获取磁盘的总量和已用量
    def getDisk(self):
        ret = self.executeCMD("df -h")
        retArr = ret.split("\n")[1].split()
       
        if len(retArr)==1:
            retArr = ret.split("\n")[2].split()
            diskAll=retArr[0]
            diskUsed=retArr[1]
        else:
            diskAll=retArr[1]
            diskUsed=retArr[2]
        self.uploadData.append({
            "endpoint": InfoMonConstants.ENDPOINT,
            "metric": "system_disk_all",
            "timestamp": self.ts,
            "step": 60,
            "value": diskAll,
            "counterType": "GAUGE",
            "tags": "",
        })
        self.uploadData.append({
            "endpoint": InfoMonConstants.ENDPOINT,
            "metric": "system_disk_used",
            "timestamp": self.ts,
            "step": 60,
            "value":diskUsed,
            "counterType": "GAUGE",
            "tags": "",
        })

    # def getDisk(self):
        # result=os.statvfs('/')
        # block_size=result.f_frsize
        # total_blocks=result.f_blocks
        # free_blocks=result.f_bfree
        # giga=1024*1024*1024
        # #giga=1000*1000*1000
        # total_size=float(total_blocks*block_size)/giga
        # free_size=float(free_blocks*block_size)/giga
        # self.uploadData.append({
        #     "endpoint": InfoMonConstants.ENDPOINT,
        #     "metric": "system_disk_all",
        #     "timestamp": self.ts,
        #     "step": 60,
        #     "value": total_size,
        #     "counterType": "GAUGE",
        #     "tags": "",
        # })
        # self.uploadData.append({
        #     "endpoint": InfoMonConstants.ENDPOINT,
        #     "metric": "system_disk_used",
        #     "timestamp": self.ts,
        #     "step": 60,
        #     "value":int(total_size)-int(free_size),
        #     "counterType": "GAUGE",
        #     "tags": "",
        # })


    # 获取磁盘信息
    def getDiskInfo(self):
        ret = self.executeCMD("iostat -x -k")
        retArr = ret.split("\n")[6].split()
        self.uploadData.append({
            "endpoint": InfoMonConstants.ENDPOINT,
            "metric": "system_read_request",
            "timestamp": self.ts,
            "step": 60,
            "value": retArr[3],
            "counterType": "GAUGE",
            "tags": "",
        })
        self.uploadData.append({
            "endpoint": InfoMonConstants.ENDPOINT,
            "metric": "system_write_request",
            "timestamp": self.ts,
            "step": 60,
            "value": retArr[4],
            "counterType": "GAUGE",
            "tags": "",
        })
        self.uploadData.append({
            "endpoint": InfoMonConstants.ENDPOINT,
            "metric": "system_disk_write",
            "timestamp": self.ts,
            "step": 60,
            "value": int(float(retArr[5]))*1024,
            "counterType": "GAUGE",
            "tags": "",
        })
        self.uploadData.append({
            "endpoint": InfoMonConstants.ENDPOINT,
            "metric": "system_used_read",
            "timestamp": self.ts,
            "step": 60,
            "value": int(float(retArr[6]))*1024,
            "counterType": "GAUGE",
            "tags": "",
        })
        self.uploadData.append({
            "endpoint": InfoMonConstants.ENDPOINT,
            "metric": "system_time_read",
            "timestamp": self.ts,
            "step": 60,
            "value": retArr[10],
            "counterType": "GAUGE",
            "tags": "",
        })
        self.uploadData.append({
            "endpoint": InfoMonConstants.ENDPOINT,
            "metric": "system_time_write",
            "timestamp": self.ts,
            "step": 60,
            "value": retArr[11],
            "counterType": "GAUGE",
            "tags": "",
        })

    # 获取tcp信息
    def getTCPInfo(self):
        ret = self.executeCMD("netstat -n | awk '/^tcp/' |grep CLOSED |wc -l")
        self.uploadData.append({
            "endpoint": InfoMonConstants.ENDPOINT,
            "metric": "system_tcp_closed",
            "timestamp": self.ts,
            "step": 60,
            "value": ret.rstrip("\n"),
            "counterType": "GAUGE",
            "tags": "",
        })
        ret = self.executeCMD("netstat -n | awk '/^tcp/' |grep LISTEN |wc -l")
        self.uploadData.append({
            "endpoint": InfoMonConstants.ENDPOINT,
            "metric": "system_tcp_listen",
            "timestamp": self.ts,
            "step": 60,
            "value": ret.rstrip("\n"),
            "counterType": "GAUGE",
            "tags": "",
        })
        ret = self.executeCMD("netstat -n | awk '/^tcp/' |grep CLOSING |wc -l")
        self.uploadData.append({
            "endpoint": InfoMonConstants.ENDPOINT,
            "metric": "system_tcp_closing",
            "timestamp": self.ts,
            "step": 60,
            "value": ret.rstrip("\n"),
            "counterType": "GAUGE",
            "tags": "",
        })
        ret = self.executeCMD("netstat -n | awk '/^tcp/' |grep ESTABLISHED |wc -l")
        self.uploadData.append({
            "endpoint": InfoMonConstants.ENDPOINT,
            "metric": "system_tcp_established",
            "timestamp": self.ts,
            "step": 60,
            "value": ret.rstrip("\n"),
            "counterType": "GAUGE",
            "tags": "",
        })
        ret = self.executeCMD("netstat -n | awk '/^tcp/' |grep FIN_WAIT1 |wc -l")
        self.uploadData.append({
            "endpoint": InfoMonConstants.ENDPOINT,
            "metric": "system_tcp_fin_wait1",
            "timestamp": self.ts,
            "step": 60,
            "value": ret.rstrip("\n"),
            "counterType": "GAUGE",
            "tags": "",
        })
        ret = self.executeCMD("netstat -n | awk '/^tcp/' |grep FIN_WAIT2 |wc -l")
        self.uploadData.append({
            "endpoint": InfoMonConstants.ENDPOINT,
            "metric": "system_tcp_fin_wait2",
            "timestamp": self.ts,
            "step": 60,
            "value": ret.rstrip("\n"),
            "counterType": "GAUGE",
            "tags": "",
        })
        ret = self.executeCMD("netstat -n | awk '/^tcp/' |grep LAST_ACK |wc -l")
        self.uploadData.append({
            "endpoint": InfoMonConstants.ENDPOINT,
            "metric": "system_tcp_last_ack",
            "timestamp": self.ts,
            "step": 60,
            "value": ret.rstrip("\n"),
            "counterType": "GAUGE",
            "tags": "",
        })
        ret = self.executeCMD("netstat -n | awk '/^tcp/' |grep SYN_RECV |wc -l")
        self.uploadData.append({
            "endpoint": InfoMonConstants.ENDPOINT,
            "metric": "system_tcp_syn_secv",
            "timestamp": self.ts,
            "step": 60,
            "value": ret.rstrip("\n"),
            "counterType": "GAUGE",
            "tags": "",
        })
        ret = self.executeCMD("netstat -n | awk '/^tcp/' |grep SYN_SENT |wc -l")
        self.uploadData.append({
            "endpoint": InfoMonConstants.ENDPOINT,
            "metric": "system_tcp_syn_sent",
            "timestamp": self.ts,
            "step": 60,
            "value": ret.rstrip("\n"),
            "counterType": "GAUGE",
            "tags": "",
        })
        ret = self.executeCMD("netstat -n | awk '/^tcp/' |grep TIME_WAIT |wc -l")
        self.uploadData.append({
            "endpoint": InfoMonConstants.ENDPOINT,
            "metric": "system_tcp_time_wait",
            "timestamp": self.ts,
            "step": 60,
            "value": ret.rstrip("\n"),
            "counterType": "GAUGE",
            "tags": "",
        })

    def getNetworkInfo(self):
        ret = self.executeCMD("cat /proc/net/dev")
        retArr = ret.split("\n")
        time.sleep(1)
        ret2 = self.executeCMD("cat /proc/net/dev")
        retArr2 = ret2.split("\n")
        for index in list(range(2, len(retArr)-1)):
            item = retArr[index].split()
            item2 = retArr2[index].split()

            tag = item[0][:-1]
            net_pkts_in = int(item2[2])-int(item[2])
            net_bytes_in = int(item2[1])-int(item[1])
            net_bytes_out = int(item2[10])-int(item[10])
            net_pkts_out = int(item2[9])-int(item[9])

            ret = self.executeCMD("ethtool " + tag + " | grep Speed")
            if ret:
                total = int(filter(lambda ch:ch in '1234567890', ret))
                self.uploadData.append({
                    "endpoint": InfoMonConstants.ENDPOINT,
                    "metric": "system_net_usage",
                    "timestamp": self.ts,
                    "step": 60,
                    "value": format(float(max(net_bytes_in,net_bytes_out)*100)/(total*1024*1024/8), '.2f'),
                    "counterType": "GAUGE",
                    "tags": tag,
                })
                self.uploadData.append({
                    "endpoint": InfoMonConstants.ENDPOINT,
                    "metric": "system_network_bytes_received_per_sec",
                    "timestamp": self.ts,
                    "step": 60,
                    "value": net_bytes_in,
                    "counterType": "GAUGE",
                    "tags": tag,
                })
                self.uploadData.append({
                    "endpoint": InfoMonConstants.ENDPOINT,
                    "metric": "system_network_bytes_send_per_sec",
                    "timestamp": self.ts,
                    "step": 60,
                    "value": net_bytes_out,
                    "counterType": "GAUGE",
                    "tags": tag,
                })
                self.uploadData.append({
                    "endpoint": InfoMonConstants.ENDPOINT,
                    "metric": "system_network_packets_received_per_sec",
                    "timestamp": self.ts,
                    "step": 60,
                    "value": net_pkts_in,
                    "counterType": "GAUGE",
                    "tags": tag,
                })
                self.uploadData.append({
                    "endpoint": InfoMonConstants.ENDPOINT,
                    "metric": "system_network_packets_send_per_sec",
                    "timestamp": self.ts,
                    "step": 60,
                    "value": net_pkts_out,
                    "counterType": "GAUGE",
                    "tags": tag,
                })

